package game.MainGame;

import game.gui.Category;
import game.gui.buttons.ArtLbl;
import game.gui.buttons.FirstLbl;
import game.gui.buttons.GeographyLbl;
import game.gui.buttons.HistoryLbl;
import game.gui.buttons.ScienceLbl;
import game.gui.buttons.SportLbl;
import game.gui.buttons.VariaLbl;
import game.gui.buttons.WorldLbl;
import game.jabberclient.Client;
import game.jabberclient.Message;
import javax.swing.JLabel;
import java.awt.Color;
import java.awt.Font;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.util.ArrayList;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JButton;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.border.LineBorder;

/**
 * GUI for the client. Listens clients actions on the GUI and sends messages
 * through client to the server.
 * 
 */
public class WorldMemoryGame extends JFrame implements ActionListener {

	private static final long serialVersionUID = 1L;
	private String host;
	private int port;
	private JTextArea lblProcess;
	private JButton login, logout, start;
	private JTextField tf;
	private JTextField tfServer, tfPort;
	private Client client;
	private JLabel label;
	private boolean connected;
	private JButton btnDie;
	private JLabel imageLbl;
	private JTextArea txtrPlayerlist;
	private HistoryLbl history1;
	private Category history;
	private Category art;
	private Category geography;
	private Category science;
	private Category sport;
	private Category varia;	

	public WorldMemoryGame(String host, int port) {
		this.host = host;
		this.port = port;
	this.setSize(900, 700);
		this.setResizable(false);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		getContentPane().setSize(new Dimension(600, 400));
		getContentPane().setFont(new Font("Calibri", Font.PLAIN, 15));
		getContentPane().setBackground(new Color(255, 248, 220));
		getContentPane().setLayout(null);
		getContentPane().setVisible(true);

		JPanel serverAndPort = new JPanel(new GridLayout(4, 2, 1, 1));

		tfServer = new JTextField(host);
		tfPort = new JTextField("" + port);
		tfPort.setHorizontalAlignment(SwingConstants.RIGHT);
		tf = new JTextField("name");
		label = new JLabel("Username");
		logout = new JButton("Logout");
		login = new JButton("Login");
		login.addActionListener(this);
		logout.addActionListener(this);
		logout.setEnabled(false); // you have to login before logout

		serverAndPort.add(label);
		serverAndPort.add(tf);
		serverAndPort.add(new JLabel("Server:  "));
		serverAndPort.add(tfServer);
		serverAndPort.add(new JLabel("Port:  "));
		serverAndPort.add(tfPort);
		serverAndPort.add(login);
		serverAndPort.add(logout);
		serverAndPort.setBounds(720, 11, 150, 150);
		serverAndPort.setBackground(new Color(255, 248, 220));
		getContentPane().add(serverAndPort);
		JPanel startPanel = new JPanel();

		start = new JButton("Start");
		start.addActionListener(this);
		startPanel.setBounds(620, 16, 100, 50);
		startPanel.add(start);
		startPanel.setBackground(new Color(255, 248, 220));
		getContentPane().add(startPanel);

		JPanel north = new JPanel();

		lblProcess = new JTextArea(6, 48);
		lblProcess.setEditable(false);
		lblProcess.setEnabled(true);
		north.setBackground(new Color(255, 248, 220));
		north.add(new JScrollPane(lblProcess));
		north.setBounds(53, 11, 550, 105);

		getContentPane().add(north);

		JLabel lblPlayers = new JLabel("Online players:");
		lblPlayers.setBounds(720, 170, 100, 14);
		getContentPane().add(lblPlayers);
		lblPlayers.setBackground(Color.yellow);

		txtrPlayerlist = new JTextArea();
		txtrPlayerlist.setBounds(720, 185, 150, 89);
		txtrPlayerlist.setBorder(new LineBorder(new Color(205, 140, 149)));
		txtrPlayerlist.setEditable(false);
		getContentPane().add(txtrPlayerlist);

		btnDie = new JButton("Die");
		btnDie.setBackground(Color.YELLOW);
		btnDie.setBounds(780, 275, 90, 90);
		getContentPane().add(btnDie);
		btnDie.setEnabled(false);
		btnDie.addActionListener(this);

		JPanel panel = new JPanel();

		imageLbl = new JLabel();
		imageLbl.setBounds(690, 275, 90, 90);
		getContentPane().add(imageLbl);

		panel.setBounds(53, 117, 550, 550);
		getContentPane().add(panel);
		panel.setLayout(null);
		JLabel cards = new JLabel("You need to collect categories:");
		cards.setBounds(670, 370, 200, 15);
		getContentPane().add(cards);

		history = new Category("History", new Color(255, 215, 0));
		art = new Category("Art", new Color(255, 48, 48));
		geography = new Category("Geography", new Color(255, 127, 36));
		science = new Category("Science", new Color(154, 205, 50));
		sport = new Category("Sport", new Color(32, 178, 170));
		varia = new Category("Varia", new Color(240, 128, 128));
		
		history.setLocation(670, 400);
		art.setLocation(731, 430);
		geography.setLocation(792, 460);
		science.setLocation(731, 491);
		sport.setLocation(670, 522);
		varia.setLocation(731, 553);
		
		getContentPane().add(history);
		getContentPane().add(art);
		getContentPane().add(geography);
		getContentPane().add(science);
		getContentPane().add(sport);
		getContentPane().add(varia);
		
		history1 = new HistoryLbl(1, this);
		history1.setBounds(90, 474, 60, 60);
		history1.getPlayers().setSize(60, 60);
		history1.getPlayers().setText("Start");
		panel.add(history1);
		HistoryLbl history2 = new HistoryLbl(8, this);
		history2.setBounds(475, 398, 60, 60);
		panel.add(history2);
		HistoryLbl history3 = new HistoryLbl(15, this);
		history3.setBounds(397, 16, 60, 60);
		panel.add(history3);
		HistoryLbl history4 = new HistoryLbl(22, this);
		history4.setBounds(15, 88, 60, 60);
		panel.add(history4);

		ArtLbl art1 = new ArtLbl(2, this);
		art1.setBounds(151, 474, 60, 60);
		panel.add(art1);
		ArtLbl art2 = new ArtLbl(9, this);
		art2.setBounds(475, 336, 60, 60);
		panel.add(art2);
		ArtLbl art3 = new ArtLbl(16, this);
		art3.setBounds(335, 16, 60, 60);
		panel.add(art3);
		ArtLbl art4 = new ArtLbl(23, this);
		art4.setBounds(15, 150, 60, 60);
		panel.add(art4);

		ScienceLbl sience1 = new ScienceLbl(3, this);
		sience1.setBounds(212, 474, 60, 60);
		panel.add(sience1);
		ScienceLbl sience2 = new ScienceLbl(10, this);
		sience2.setBounds(475, 274, 60, 60);
		panel.add(sience2);
		ScienceLbl sience3 = new ScienceLbl(17, this);
		sience3.setBounds(273, 16, 60, 60);
		panel.add(sience3);
		ScienceLbl sience4 = new ScienceLbl(24, this);
		sience4.setBounds(15, 212, 60, 60);
		panel.add(sience4);

		GeographyLbl geography1 = new GeographyLbl(4, this);
		geography1.setBounds(273, 474, 60, 60);
		panel.add(geography1);
		GeographyLbl geography2 = new GeographyLbl(11, this);
		geography2.setBounds(475, 212, 60, 60);
		panel.add(geography2);
		GeographyLbl geography3 = new GeographyLbl(18, this);
		geography3.setBounds(212, 16, 60, 60);
		panel.add(geography3);
		GeographyLbl geography4 = new GeographyLbl(25, this);
		geography4.setBounds(15, 274, 60, 60);
		panel.add(geography4);

		SportLbl sport1 = new SportLbl(5, this);
		sport1.setBounds(335, 474, 60, 60);
		panel.add(sport1);
		SportLbl sport2 = new SportLbl(12, this);
		sport2.setBounds(475, 150, 60, 60);
		panel.add(sport2);
		SportLbl sport3 = new SportLbl(19, this);
		sport3.setBounds(151, 16, 60, 60);
		panel.add(sport3);
		SportLbl sport4 = new SportLbl(26, this);
		sport4.setBounds(15, 336, 60, 60);
		panel.add(sport4);

		VariaLbl varia1 = new VariaLbl(6, this);
		varia1.setBounds(397, 474, 60, 60);
		panel.add(varia1);
		VariaLbl varia2 = new VariaLbl(13, this);
		varia2.setBounds(475, 88, 60, 60);
		panel.add(varia2);
		VariaLbl varia3 = new VariaLbl(20, this);
		varia3.setBounds(90, 16, 60, 60);
		panel.add(varia3);
		VariaLbl varia4 = new VariaLbl(27, this);
		varia4.setBounds(15, 398, 60, 60);
		panel.add(varia4);

		WorldLbl world1 = new WorldLbl(7, this);
		world1.setBounds(470, 469, 70, 70);
		panel.add(world1);
		WorldLbl world2 = new WorldLbl(14, this);
		world2.setBounds(470, 11, 70, 70);
		panel.add(world2);
		WorldLbl world3 = new WorldLbl(21, this);
		world3.setBounds(10, 11, 70, 70);
		panel.add(world3);
		WorldLbl world4 = new WorldLbl(28, this);
		world4.setBounds(10, 469, 70, 70);
		panel.add(world4);

		JPanel panel_1 = new JPanel();
		panel_1.setBounds(212, 212, 121, 121);
		panel.setBorder(new LineBorder(new Color(220, 20, 60)));
		panel.setBackground(new Color(255, 248, 220));
		panel.add(panel_1);
		panel_1.setLayout(null);

		JLabel lblFinish = new JLabel("FINISH");
		lblFinish.setHorizontalAlignment(SwingConstants.CENTER);
		lblFinish.setBounds(10, 11, 101, 99);
		panel_1.add(lblFinish);
		setVisible(true);

	}
	
	public JButton getStart() {
		return start;
	}
	public JButton getBtnDie() {
		return btnDie;
	}
	public HistoryLbl getHistory1() {
		return history1;
	}
	/**
	 * Enables login button if connection was not made.
	 */
	public void connectionFailed() {
		login.setEnabled(true);
		logout.setEnabled(false);

		label.setText("Username");
		tf.setText("name");
		// reset port number and host name as a construction time
		tfPort.setText("" + port);
		tfServer.setText(host);
		// let the user change them
		tfServer.setEditable(false);
		tfPort.setEditable(false);

		// don't react to a <CR> after the username
		tf.removeActionListener(this);
		connected = false;
	}

	/**
	 * Client chat and all other messages to be displayed on the gui.
	 * 
	 * @param str
	 *            message
	 */
	public void append(String str) {
		lblProcess.append(str);
		lblProcess.setCaretPosition(lblProcess.getText().length() - 1);
	}

	/**
	 * Removes player id and name from player list.
	 * 
	 * @param msg
	 *            player id & name
	 */
	public void removePlayerName(String msg) {
		String[] message = msg.split(" ");
		String id = message[0];
		String name = message[1];
		if (txtrPlayerlist.getText().contains(id + " " + name)) {
			txtrPlayerlist.setText(txtrPlayerlist.getText().replaceAll(
					id + " " + name, ""));
			txtrPlayerlist.setText(txtrPlayerlist.getText().replaceAll(
					"[\\r\\n]+", "\n"));
		}
	}

	/**
	 * Adds player id and name to player list.
	 * 
	 * @param str
	 *            player id & name
	 */
	public void appendPlayer(String str) {
		txtrPlayerlist.append(str);
	}

	/**
	 * Listens for buttons clicked.
	 */
	public void actionPerformed(ActionEvent e) {
		Object o = e.getSource();
		if (o == logout) {
			client.sendMessage(new Message(Message.LOGOUT, client.getClientId()
					+ " " + client.getClientButton().getIndex()));
			System.exit(0);
		}
		if (connected) {
			if (o == start) {
				client.sendMessage(new Message(Message.START, ""));
				return;
			}
			if (o == btnDie) {
				rollDie();
				repaint();
				return;
			}
			if (o.getClass().getSuperclass().equals(
					history1.getClass().getSuperclass())) {
				ArrayList<FirstLbl> buttons = history1.getButtons();
				FirstLbl but = null;
				for (FirstLbl f : buttons) {
					if (f.hashCode() == o.hashCode()) {
						if (f.popQuestion(this)) {
							but = f;
							String category = but.getClass().getSimpleName();
							if (f.getIndex() == 7 || f.getIndex() == 14
									|| f.getIndex() == 21 || f.getIndex() == 28) {
								category = f.getCategory();
							}
							System.out.println(category);
							String right = removeCategory(category);
							client.setClientButton(but);
							client.sendMessage(new Message(Message.MOVE, client
									.getClientId()
									+ " " + but.getIndex()));						
							client.sendMessage(new Message(Message.MESSAGE,
									client.getName() + " has answered " + right
											+ " question correctly!"));
							
							if (client.isArt() && client.isGeography()
									&& client.isHistory() && client.isScience()
									&& client.isSport() && client.isVaria()) {
								client.sendMessage(new Message(Message.VICTORY,
										""));
							}
						} else {
							client.sendMessage(new Message(Message.MESSAGE,
									client.getName()
											+ " didn't get the right answer."));
						}
						client.sendMessage(new Message(Message.NEXT, ""));
						append("Please wait for others to end their turn...\n");
					}
				}
				// unactiactivates all buttons
				for (FirstLbl f : buttons) {
					if (f.isEnabled() == true) {
						f.unactivate();
					}

				}
			}
			// simple chat message
			if (!tf.getText().isEmpty()) {
				client.sendMessage(new Message(Message.MESSAGE, client
						.getName()
						+ ": " + tf.getText()));
				tf.setText("");
			}
			return;
		}
		if (o == login) {
			String username = tf.getText().trim();
			// returns if username, server or port is not set.
			if (username.length() == 0)
				return;
			String server = tfServer.getText().trim();
			if (server.length() == 0)
				return;
			String portNumber = tfPort.getText().trim();
			if (portNumber.length() == 0)
				return;
			int port = 0;
			try {
				port = Integer.parseInt(portNumber);
			} catch (Exception en) {
				return;
			}
			// creates new client
			client = new Client(server, port, username, this, history1);
			if (!client.start())
				return;
			tf.setText("");
			label.setText("Message");
			connected = true;
			login.setEnabled(false);
			logout.setEnabled(true);
			tfServer.setEditable(false);
			tfPort.setEditable(false);
			tf.addActionListener(this);
		}

	}

	/**
	 * If question was answered correctly, removes respectively category from
	 * GUI and sets respectively category boolean true for later winner check.
	 * 
	 * @param category
	 *            Category name, which was answered correctly.
	 * @return Returns category name without "Lbl" to display correctly to other
	 *         clients.
	 */
	private String removeCategory(String category) {
		if (category.equalsIgnoreCase("ArtLbl")) {
			art.setVisible(false);
			client.setArt(true);
			return "Art";
		} else if (category.equalsIgnoreCase("GeographyLbl")) {
			geography.setVisible(false);
			client.setGeography(true);
			return "Geography";
		} else if (category.equalsIgnoreCase("HistoryLbl")) {
			history.setVisible(false);
			client.setHistory(true);
			return "History";
		} else if (category.equalsIgnoreCase("ScienceLbl")) {
			science.setVisible(false);
			client.setScience(true);
			return "Science";
		} else if (category.equalsIgnoreCase("SportLbl")) {
			sport.setVisible(false);
			client.setSport(true);
			return "Sport";
		} else if (category.equalsIgnoreCase("VariaLbl")) {
			varia.setVisible(false);
			client.setVaria(true);
			return "Varia";
		}
		return category;
	}

	/**
	 * Die image for random roll.
	 */
	private void rollDie() {
		try {
			String path = "res/" + randomize() + ".jpg";
			ImageIcon image = new ImageIcon(path);
			imageLbl.setIcon(image);
		} catch (IOException e) {
		}
	}

	/**
	 * Rolls a random number from 0-5.
	 * 
	 * @return returns a string of rolled die side.
	 * @throws IOException
	 */
	private String randomize() throws IOException {
		int i = (int) (Math.random() * 6);
		String dice = "";
		int number = 0;
		switch (i) {
		case 0:
			dice = "one";
			number = 1;
			break;
		case 1:
			number = 2;
			dice = "two";
			break;
		case 2:
			number = 3;
			dice = "three";
			break;
		case 3:
			number = 4;
			dice = "four";
			break;
		case 4:
			number = 5;
			dice = "five";
			break;
		case 5:
			number = 6;
			dice = "six";
			break;
		}
		client.getNetOut().writeObject(
				new Message(Message.DICE, client.getName()
						+ " rolled a die and got " + dice + "."));
		getMoveOptions(client, number);
		return dice;
	}

	/**
	 * Enables buttons accordingly to the random roll of die.
	 * 
	 * @param c
	 * @param number
	 */
	public void getMoveOptions(Client c, int number) {
		int clientIndex = c.getClientButton().getIndex();
		int forward = (clientIndex + number) % 28;
		int backward = (clientIndex - number + 28) % 28;
		for (FirstLbl f : FirstLbl.getButtons()) {
			if ((f.getIndex() == forward) || (f.getIndex() == backward)) {
				f.activate();
			} else if (f.getIndex() == 28
					&& ((forward == 0) || (backward == 0))) {
				f.activate();
			}

		}
		btnDie.setEnabled(false);
	}

	public static void main(String[] args) {
		new WorldMemoryGame("localhost", 1500);
	}

}
